#include <fcntl.h>
#include <rtthread.h>
#ifdef FINSH_USING_MSH
#include <finsh.h>
#endif
#include "dfs_fs.h"
#include "factory_api.h"
#include "fal.h"
#include "ulog.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define ARR_LEN 100

#define DBG_ENABLE
#define DBG_LVL DBG_LOG
#define DBG_SECTION_NAME "file_test"
#include "uc_log.h"

#define SD_CARD_PATH "/sd"
#define DEVICE_NAME "sd0"
#define SD_PARTITION_NAME "sd"

static void factory_feedback(factory_test_type_e type, factory_test_state_e state, char *remark)
{
    switch (type)
    {
    case EXTERNAL_FLASH_TEST:
        factory_test_result(type, factory_get_key(type), state, remark);
        break;
    case SD_TEST:
        factory_test_result(type, factory_get_key(type), state, remark);
        break;
    default:
        break;
    }
}

static int factory_sd_mount(factory_test_type_e type)
{
    int card_fd = -1;
    card_fd = open(SD_CARD_PATH, O_DIRECTORY | O_CREAT);
    if (card_fd < 0)
    {
        if (rt_get_errno() != -EEXIST)
        {
            TRACE_E("dir %s open&create error, exit", SD_CARD_PATH);
            factory_feedback(type, FACTORY_TEST_FAIL, "open mount sd dir fail");
            return -RT_ERROR;
        }
        TRACE_D("dir %s already exist", SD_CARD_PATH);
    }
    else
    {
        TRACE_D("create dir %s success", SD_CARD_PATH);
        close(card_fd);
    }

    // elm
    char *fs_type = "elm";

    // 挂载sd卡
    if (dfs_mount(DEVICE_NAME, SD_CARD_PATH, fs_type, 0, 0))
    {
        TRACE_E("mount %s again error, exit.", SD_PARTITION_NAME);
        factory_feedback(type, FACTORY_TEST_FAIL, "mount sd card fail");
        return -RT_ERROR;
    }

    TRACE_D("mount %s partition on %s success", SD_PARTITION_NAME, SD_CARD_PATH);

    // 格式化sd卡
    if (dfs_mkfs(fs_type, DEVICE_NAME))
    {
        TRACE_E("mkfs %s partition error, exit.", SD_PARTITION_NAME);
        factory_feedback(type, FACTORY_TEST_FAIL, "format sd card fail");
        return -RT_ERROR;
    }

    TRACE_D("mkfs %s partiton ok, try mount %s again.", SD_PARTITION_NAME, SD_PARTITION_NAME);

    return 0;
}

int file_wr_test(factory_test_type_e type, char *file_name)
{
    int sd_fd = 0;
    int i = 0;
    char write_buf[ARR_LEN];
    char read_buf[ARR_LEN];
    int result = 0;

    if (type == SD_TEST)
    {
        result = factory_sd_mount(type);
        if (result != 0)
        {
            return -RT_ERROR;
        }
    }

    memset(write_buf, '1', ARR_LEN);

    sd_fd = open(file_name, O_CREAT | O_RDWR | O_TRUNC);
    if (sd_fd < 0)
    {
        TRACE_E("open file %s failed", file_name);
        factory_feedback(type, FACTORY_TEST_FAIL, "open file fail");
        return -RT_ERROR;
    }

    result = write(sd_fd, write_buf, ARR_LEN);
    if (result != ARR_LEN)
    {
        TRACE_E("write file %s failed", file_name);
        factory_feedback(type, FACTORY_TEST_FAIL, "write file fail");
        return -RT_ERROR;
    }

    fsync(sd_fd);

    close(sd_fd);
    sd_fd = open(file_name, O_RDONLY);
    if (sd_fd < 0)
    {
        TRACE_E("open file %s failed", file_name);
        factory_feedback(type, FACTORY_TEST_FAIL, "open file fail");
        return -RT_ERROR;
    }

    result = read(sd_fd, read_buf, ARR_LEN);
    if (result < 0)
    {
        TRACE_E("read file %s failed", file_name);
        factory_feedback(type, FACTORY_TEST_FAIL, "read file fail");
        return -RT_ERROR;
    }

    if (rt_strncmp(read_buf, write_buf, ARR_LEN) != 0)
    {
        TRACE_E("read file data is not equal write data\n");
        for (i = 0; i < ARR_LEN; i++)
        {
            TRACE_D("readbuf is %d,i is %d", read_buf[i], i);
        }
        factory_feedback(type, FACTORY_TEST_FAIL, "read write data unequal");
        return -RT_ERROR;
    }

    TRACE_D("read file data is equal write data,successful\n");

    close(sd_fd);

    factory_feedback(type, FACTORY_TEST_SUCCESS, "NULL");

    return 0;
}

int factory_sd_card_test(int argc, char **argv)
{
    int ret = 0;
    ret = file_wr_test(SD_TEST, "/sd/test.txt");
    return ret;
};

int factory_flash_test(int argc, char **argv)
{
    int ret = 0;
    ret = file_wr_test(EXTERNAL_FLASH_TEST, "/logs/flash.txt");
    return ret;
}
#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT_ALIAS(factory_sd_card_test, sd_test, sd card file write read test);
MSH_CMD_EXPORT_ALIAS(factory_flash_test, flash_test, flash file write read test);
#endif
